home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 03 - 1987 / 03.03 Mar 87 / Pascal Graf3D / threeD.pas (turbo) < prev   
Encoding:
Text File  |  1986-12-07  |  14.9 KB  |  504 lines  |  [TEXT/TPAS]

  1. {******************************************    }
  2. {    Graf3D Demo                                                    }
  3. {                                                                            }
  4. {    by Scott Berfield                                           }
  5. {    for MacTutor magazine                                    }
  6. {                                                                            }
  7. {    History: Version one October 29, 1986        }
  8. {        using Lightspeed Pascal    converted to     }
  9. {    Turbo Pascal December 7, 1986                }
  10. {                                                                            }
  11. {******************************************    }
  12.  
  13. PROGRAM DEMO;
  14. {$R My Threed.rsrc} {link the resource file}
  15. {$U-}               {Turn off default USES}
  16. {$B+}               {Set the bundle bit}
  17. {$D+}               {Turn on procedure names for debugging}
  18. {$T APPL!@#$}       {Set creator and type}
  19.  
  20.     USES
  21.     MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, fixmath, graf3d;    
  22.     
  23.  CONST
  24.         object = 1;    {flag indicating which we are currently rotating}
  25.         world = 2;
  26.         hellfreezesover = false;        {A never-changing boolean for eventloop}
  27.         VIEWwindowID = 32000;        {ID of our drawing window}
  28.         INPUTWINDOWID = 32001;    {ID of our control window}
  29.         APPLEM = 0;                    {Menu indices}
  30.         FILEM = 1;
  31.         EDITM = 2;
  32.         SWITCHM = 3;
  33.         appleID = 128;                {Menu resource IDs}
  34.         fileID = 129;
  35.         editID = 130;
  36.         SWITCHID = 131;
  37.         lastmenu = 3;                    {How many menus}
  38.         aboutID = 128;                {About alert resource ID}
  39.         UndoItem = 1;                    {Menu item codes}
  40.         cutitem = 3;
  41.         copyitem = 4;
  42.         pasteitem = 5;
  43.         clearitem = 6;
  44.         XScrollID = 128;                {Scroll bar resource IDs}
  45.         YScrollID = 129;
  46.         ZScrollID = 130;
  47.         XMIN = -200;                    {Limits for object space (set with LOOKAT)}
  48.         YMIN = -200;
  49.         ZMIN = -200;
  50.         XMAX = 200;
  51.         YMAX = 200;
  52.         ZMAX = 200;
  53.  
  54.     VAR
  55.         fromupdate : boolean;
  56.         whichcontrol : controlhandle;                        {which control was hit?}
  57.         xscroll, yscroll, zscroll : controlhandle;                {storage for scrollbars}
  58.         myMenus : ARRAY[0..lastmenu] OF menuhandle;    {our menus}
  59.         INPUTWINDOW : windowptr;                        {pointers to our windows}
  60.         VIEWWindow : windowPtr;
  61.         Wrecord : windowrecord;                            {Storage for our windows}
  62.         Wrecord2 : windowrecord;
  63.         gport3d : port3d;                                    {Our 3D grafport}
  64.         XROT, YROT, ZROT : integer;                        {current scrollbar settings}
  65.         OXROT, OYROT, OZROT : integer;                    {old scroll bar settings}
  66.         which : integer;                                        {Object or world rotation?}
  67.         XSpacerot, YSpaceRot, ZSpaceRot : integer;        {how much is space rotated?}
  68.         XObjRot, YObjRot, ZObjRot : integer;                {how much is the object rotated?}
  69.         Dtetra, tetra : ARRAY[1..4] OF point3d;                {the original and the transformed tetrahedra}
  70.         delta : integer;                                         {inc or dec the scroll bars}
  71.  
  72.     PROCEDURE init;    {set everything up}
  73.     BEGIN
  74.         initgraf(@thePort);
  75.         initgrf3d(@theport3d);    {this is the graf3D equivalent. It IS NOT optional}
  76.         InitFonts;
  77.         FlushEvents(everyEvent, 0);
  78.         InitWindows;
  79.         InitMenus;
  80.         TEInit;
  81.         InitDialogs(NIL);
  82.         InitCursor;
  83.         XROT := 0;            {Set initial values for everything}
  84.         YROT := 0;
  85.         ZROT := 0;
  86.         OXROT := 1;
  87.         OYROT := 1;
  88.         OZROT := 1;
  89.         XSpaceRot := 0;
  90.         YSpaceRot := 0;
  91.         ZSpaceRot := 0;
  92.         XObjRot := 0;
  93.         YObjRot := 0;
  94.         ZObjRot := 0;
  95.         which := object;        {the default is to rotate the object}
  96.         setpt3d(tetra[1], 0, -6553600, 0); {set the tetrahedron's vertices}
  97.         setpt3d(tetra[2], -1638400, -3276800, 0);
  98.         setpt3d(tetra[3], 1638400, -3276800, 0);
  99.         setpt3d(tetra[4], 0, -4915200, 1638400);
  100.         DTetra := tetra;
  101.     END;                 {init}
  102.  
  103.     PROCEDURE drawvalues;        {Draw the current scroll bar settings as text}
  104.         VAR
  105.             text1, text2, text3 : str255;
  106.             trect : rect;
  107.     BEGIN
  108.         IF (OXROT <> XROT) OR (OYROT <> YROT) OR (OZROT <> ZROT) OR (fromupdate) THEN
  109.             BEGIN                                        {we only draw them if only if something has changed}
  110.                 setrect(trect, 0, 45, 512, 65);
  111.                 setport(inputwindow);
  112.                 eraserect(trect);
  113.                 penpat(black);
  114.                 textfont(0);
  115.                 textsize(12);
  116.                 numtostring(xrot, text1);
  117.                 numtostring(yrot, text2);
  118.                 numtostring(zrot, text3);
  119.                 moveto(10, 55);
  120.                 drawstring(text1);
  121.                 moveto(175, 55);
  122.                 drawstring(text2);
  123.                 moveto(340, 55);
  124.                 drawstring(text3);
  125.                 OXROT := XROT;
  126.                 OYROT := YROT;
  127.                 OZROT := ZROT;
  128.             END;
  129.     END;                 {drawvalues}
  130.  
  131.     PROCEDURE drawlabels;    {label the scroll bars}
  132.         VAR
  133.             labelrect : rect;
  134.     BEGIN
  135.         setrect(labelrect, 0, 0, 512, 24);
  136.         setport(inputwindow);
  137.         eraserect(labelrect);
  138.         textfont(0);        {Chicago font}
  139.         textsize(12);        {12 point}
  140.         penpat(black);    {make sure we can see it}
  141.         CASE which OF    {which labels do we draw?}
  142.             object : 
  143.                 BEGIN
  144.                     moveto(10, 19);
  145.                     drawstring('X Rotation');
  146.                     moveto(175, 19);
  147.                     drawstring('Y Rotation');
  148.                     moveto(340, 19);
  149.                     drawstring('Z Rotation');
  150.                 END;
  151.             world : 
  152.                 BEGIN
  153.                     moveto(10, 19);
  154.                     drawstring('Pitch');
  155.                     moveto(175, 19);
  156.                     drawstring('Yaw');
  157.                     moveto(340, 19);
  158.                     drawstring('Roll');
  159.                 END;
  160.         END;
  161.     END;            {drawlabels}
  162.  
  163.     PROCEDURE drawgrid;        {Draw the “space grid”}
  164.         VAR
  165.             i : integer;
  166.     BEGIN                                {all coordinates must be in fixed point — multiply by 65536}
  167.         pitch(XSPACEROT * 65536);    {rotate space by x value...}
  168.         YAW(YSPACEROT * 65536);    {rotate space by y value...}
  169.         ROLL(ZSPACEROT * 65536);    {rotate space by z value...}
  170. {now draw the grid in the newly rotated space}
  171.         moveto3d(-6553600, 0, -6553600);         {-100,0,-100}
  172.         lineto3d(-6553600, 0, 6553600);            {etc...}
  173.         lineto3d(6553600, 0, 6553600);
  174.         lineto3d(6553600, 0, -6553600);
  175.         lineto3d(-6553600, 0, -6553600);
  176.         moveto3d(0, 0, -6553600);
  177.         lineto3d(0, 0, 6553600);
  178.         moveto3d(-6553600, 0, 0);
  179.         lineto3d(6553600, 0, 0);
  180. {when we leave (to go back to procedure drawview) space is still rotated}
  181.     END;                                {drawgrid}
  182.  
  183.     PROCEDURE drawtetra;    {draw our object}
  184.     BEGIN
  185.         moveto3d(Dtetra[1].x, Dtetra[1].y, Dtetra[1].z);    {we draw using the DTetra array which}
  186.         lineto3d(Dtetra[2].x, Dtetra[2].y, Dtetra[2].z);        {holds the transformed coordinates}
  187.         lineto3d(Dtetra[3].x, Dtetra[3].y, Dtetra[3].z);        {Note that point3D's are already in}
  188.         lineto3d(Dtetra[1].x, Dtetra[1].y, Dtetra[1].z);        {fixed - point }
  189.         lineto3d(Dtetra[4].x, Dtetra[4].y, Dtetra[4].z);
  190.         moveto3d(Dtetra[2].x, Dtetra[2].y, Dtetra[2].z);
  191.         lineto3d(Dtetra[4].x, Dtetra[4].y, Dtetra[4].z);
  192.         lineto3d(Dtetra[3].x, Dtetra[3].y, Dtetra[3].z);
  193.     END;                        {drawtetra}
  194.  
  195.     PROCEDURE drawview;    {draw the contents of the view window using current transform matrix}
  196.     BEGIN
  197.         setport(viewwindow);    {where we need to be to draw}
  198.         penpat(black);            {eraser color}
  199.         paintrect(theport^.portrect);    {erase the screen}
  200.         penpat(white);            {line color}
  201.         drawgrid;                    {draw the plane — space has been rotated when we return}
  202.         drawtetra;                {draw the object}
  203.         identity;                    {reset the transform matrix so we can figure next setting}
  204.         setport(inputwindow);    {Back to the control window for more scroll bar action!}
  205.     END;                            {Drawview}
  206.  
  207.     PROCEDURE drawinput;    {Draw the control window}
  208.     BEGIN
  209.         setport(inputwindow);
  210.         drawvalues;
  211.         drawlabels;
  212.         Drawcontrols(inputwindow);
  213.     END;                            {drawinput}
  214.  
  215.     PROCEDURE TRANS;    {transformation based on current scroll bar settings}
  216.         VAR
  217.             i : integer;
  218.     BEGIN
  219.         PITCH(XROT * 65536);    {x rotation}
  220.         YAW(YROT * 65536);    {y rotation}
  221.         ROLL(ZROT * 65536);    {z rotation}
  222.         IF which = object THEN    {if we are rotating the object...}
  223.             FOR i := 1 TO 4 DO
  224.                 BEGIN
  225.                     transform(tetra[i], Dtetra[i]);    {we apply the matrix to each point in the virgin tetra and}
  226.                 END;                                    {store it in the drawing tetra}
  227.         identity;                    {in any case, we reset the matrix before we draw the window}
  228.         drawview;                {so that the drawview procedure can control the global viewpoint}
  229.     END;                {TRANS}
  230.  
  231.  
  232.     PROCEDURE updateRots;    {update values from scroll bars}
  233.     BEGIN
  234.         XROT := GETCTLVALUE(XSCROLL);    {get the current values}
  235.         YROT := GETCTLVALUE(YSCROLL);
  236.         ZROT := GETCTLVALUE(ZSCROLL);
  237.         DrawValues;                            {draw them}
  238.         CASE which OF
  239.             object :                                 {which values need updating?}
  240.                 BEGIN
  241.                     XObjRot := XROT;
  242.                     YOBJROT := YROT;
  243.                     ZOBJROT := ZROT;
  244.                     TRANS;
  245.                 END;
  246.             world : 
  247.                 BEGIN
  248.                     XspaceRot := XROT;
  249.                     YspaceROT := YROT;
  250.                     ZspaceROT := ZROT;
  251.                     drawview;
  252.                 END;
  253.         END;
  254.     END;                    {updaterots}
  255.  
  256.  
  257.     PROCEDURE dowindows;        {set up the windows and the 3D stuff}
  258.         VAR
  259.             Vrect : rect;
  260.     BEGIN
  261.         InputWindow := GetNewWindow(INPUTWINDOWID, @Wrecord2, POINTER(-1));
  262.         xScroll := GetNewControl(XScrollID, InputWindow);
  263.         yScroll := GetNewControl(YScrollID, InputWindow);
  264.         zScroll := GetNewControl(ZScrollID, InputWindow);
  265.         ViewWindow := GetNewWindow(VIEWWINDOWID, @Wrecord, POINTER(-1));
  266. {set up a 3D grafport (it uses the reg. grafport for drawing}
  267.         Open3DPort(@gPort3D);
  268.         setport3d(@gPort3d);
  269.         viewport(viewwindow^.portbits.bounds);    {set the drawing area to the full window}
  270.         lookat(XMIN * 65536, YMIN * 65536, XMAX * 65536, YMAX * 65536);    {set the image space}
  271. {set the angle… 25° = human field of view.  0°=no persp.  80°=fish-eye lens}
  272.         viewangle(1638400);     {25° * 65536}
  273.     END;                            {doWindows}
  274.  
  275.  
  276.     PROCEDURE domenus;    {set up menus}
  277.         VAR
  278.             i : integer;
  279.     BEGIN
  280.         myMenus[appleM] := GetMenu(appleID);
  281.         AddResMenu(myMenus[appleM], 'DRVR');
  282.         myMenus[FileM] := GetMenu(fileID);
  283.         myMenus[EditM] := GetMenu(editID);
  284.         mymenus[SwitchM] := GetMenu(switchID);
  285.         FOR i := appleM TO lastmenu DO
  286.             insertMenu(myMenus[i], 0);
  287.         SetItemIcon(myMenus[0], 1, 195);
  288.         DrawMenuBar;
  289.     END;        {doMenus}
  290.  
  291.     PROCEDURE aboutme;    {do about box}
  292.         VAR
  293.             foo : integer;
  294.     BEGIN
  295.         foo := alert(aboutID, NIL);
  296.     END;        {aboutme}
  297.  
  298.  
  299.     PROCEDURE applfile (theItem : integer);        {handle file menu}
  300.     BEGIN
  301.         exittoshell;        {they chose Quit}
  302.     END;            {applfile}
  303.  
  304.     PROCEDURE DoCommand (theCommand : LongInt);    {handle menu choices}
  305.         VAR
  306.             theMenu, theItem : integer;
  307.             name : str255;
  308.             RefNum : integer;
  309.             dum : integer;
  310.             blah : boolean;
  311.     BEGIN
  312.         theMenu := hiWord(theCommand);
  313.         theItem := loWord(theCommand);
  314.         CASE theMenu OF
  315.             AppleID : 
  316.                 BEGIN
  317.                     IF (theItem = 1) THEN
  318.                         AboutMe                                                {about box}
  319.                     ELSE
  320.                         BEGIN
  321.                             getItem(myMenus[appleM], theItem, name);        {selected a desk accessory}
  322.                             dum := OpenDeskAcc(Name)
  323.                         END;         {else}
  324.                 END;             {appleM}
  325.  
  326.             FileID : 
  327.                 ApplFile(theItem);
  328.  
  329.             EditID : 
  330.                 blah := systemEdit(theItem - 1);
  331.  
  332.             SwitchID : 
  333.                 BEGIN
  334.                     CASE which OF            {adjust menuand controls to reflect which we are rotating now}
  335.                         object :                 {we were rotating the object, now we switch to rotating space}
  336.                             BEGIN
  337.                                 which := world;
  338.                                 setitem(mymenus[switchM], 1, 'Rotate Object');
  339.                                 setport(inputwindow);
  340.                                 drawlabels;
  341.                                 setctlvalue(xscroll, xspacerot);    {pick up the settings from the space values}
  342.                                 setctlvalue(yscroll, yspacerot);
  343.                                 setctlvalue(zscroll, zspacerot);
  344.                                 xrot := xspacerot;                    {update our holders}
  345.                                 yrot := yspacerot;
  346.                                 zrot := zspacerot;
  347.                                 drawvalues;                            {draw the values for the scroll bars}
  348.                             END;                        {object case}
  349.                         world : 
  350.                             BEGIN                    {switching from world to object rotations}
  351.                                 which := object;
  352.                                 setitem(mymenus[switchM], 1, 'Rotate Space');
  353.                                 setport(inputwindow);
  354.                                 drawlabels;
  355.                                 setctlvalue(xscroll, xobjrot);
  356.                                 setctlvalue(yscroll, yobjrot);
  357.                                 setctlvalue(zscroll, zobjrot);
  358.                                 xrot := xobjrot;
  359.                                 yrot := yobjrot;
  360.                                 zrot := zobjrot;
  361.                                 drawvalues;
  362.                             END;                    {world case}
  363.                         OTHERWISE
  364.                     END;            {case which of}
  365.                 END;    {switch menu case}
  366.             OTHERWISE
  367.         END;     {case theMenu}
  368.         hiliteMenu(0);    {turn off menu hilight}
  369.     END; {doCommand}
  370.  
  371.     PROCEDURE changearrow;
  372.     BEGIN
  373.         setctlvalue(whichcontrol, getctlvalue(whichcontrol) + delta);
  374.         updaterots;
  375.     END;
  376.  
  377.     PROCEDURE ApplMouseDown (theWindow : windowPtr;
  378.                                     MousePoint : point);        {handle scroll bars}
  379.         VAR
  380.             partcode : integer;
  381.             dummy, temp : integer;
  382.     BEGIN
  383.         IF theWindow = inputwindow THEN
  384.             BEGIN
  385.                 setport(inputwindow);
  386.                 globaltolocal(mousepoint);
  387.                 partcode := findcontrol(mousepoint, theWindow, whichcontrol);
  388.                 CASE partcode OF
  389.                     inupbutton : 
  390.                         BEGIN
  391.                             delta := -1;
  392.                             dummy := trackcontrol(whichcontrol, mousepoint, @changearrow);
  393.                         END;
  394.                     indownbutton : 
  395.                         BEGIN
  396.                             delta := 1;
  397.                             dummy := trackcontrol(whichcontrol, mousepoint, @changearrow);
  398.                         END;
  399.                     inpageup : 
  400.                         BEGIN
  401.                             delta := -10;
  402.                             dummy := trackcontrol(whichcontrol, mousepoint, @changearrow);
  403.                         END;
  404.                     inpagedown : 
  405.                         BEGIN
  406.                             delta := 10;
  407.                             dummy := trackcontrol(whichcontrol, mousepoint, @changearrow);
  408.                         END;
  409.                     inthumb : 
  410.                         BEGIN
  411.                             temp := getctlvalue(whichcontrol);
  412.                             dummy := trackcontrol(whichcontrol, mousepoint, NIL);
  413.                             IF getctlvalue(whichcontrol) <> temp THEN
  414.                                 updaterots;
  415.                         END;
  416.                     OTHERWISE
  417.                 END;    {case partcode of}
  418.             END;        {if}
  419.     END;         {applMouseDown}
  420.  
  421.  
  422.     PROCEDURE DoKeyDown (Event : EventRecord);        {they pressed a key}
  423.         VAR
  424.             CharCode : char;
  425.     BEGIN
  426.         CharCode := chr(Event.message MOD 256);
  427.         IF BitAnd(Event.modifiers, CmdKey) = CmdKey THEN        {must of been a command key, right?}
  428.             DoCommand(MenuKey(CharCode))                            {pass it to menu handler}
  429.     END;  { DoKeyDown }
  430.  
  431.     PROCEDURE EventLoop;        {the meat of the Mac application — process those events!}
  432.         VAR
  433.             saveport : GrafPtr;
  434.             GotEvent : boolean;
  435.             NewEvent : EventRecord;
  436.             WhichWindow : WindowPtr;
  437.             Key : char;
  438.             KeyCommand : LongInt;
  439.     BEGIN
  440.         flushevents(everyevent, 0);
  441.         REPEAT
  442.             GotEvent := GetNextEvent(EveryEvent, NewEvent);
  443.             IF GotEvent THEN
  444.                 BEGIN
  445.                     CASE NewEvent.What OF
  446.                         mouseDown : 
  447.                             BEGIN
  448.                                 CASE FindWindow(NewEvent.where, whichWindow) OF
  449.                                     inMenuBar : 
  450.                                         doCommand(menuSelect(NewEvent.where));
  451.                                     inSysWindow : 
  452.                                         SystemClick(newEvent, whichWindow);
  453.                                     inContent : 
  454.                                         applMouseDown(whichWindow, NewEvent.where); {case inContent}
  455.                                     inGoAway : 
  456.                                         IF TrackGoAway(whichWindow, NewEvent.Where) THEN
  457.                                             BEGIN
  458.                                                 ExitToShell;
  459.                                             END;
  460.                                     inDrag : 
  461.                                         IF whichWindow <> FrontWindow THEN
  462.                                             SelectWindow(whichWindow)
  463.                                         ELSE
  464.                                             applMouseDown(whichWindow, NewEvent.where);
  465.                                     OTHERWISE
  466.                                 END; {case FWReturnCode}
  467.                             END; {case mouseDown}
  468.  
  469.                         KeyDown : 
  470.                             BEGIN
  471.                                 doKeyDown(newEvent);
  472.                             END; {Case KeyDown}
  473.  
  474.                         UpdateEvt : 
  475.                             BEGIN
  476.                                 getport(saveport);            {store current grafport}
  477.                                 setport(viewwindow);        {set it to the viewwindow}
  478.                                 beginupdate(viewwindow);
  479.                                 drawview;
  480.                                 endupdate(viewwindow);
  481.                                 setport(inputwindow);        {now do the control window}
  482.                                 beginupdate(inputwindow);
  483.                                 fromupdate := true;            {used to draw the values if needed}
  484.                                 drawinput;
  485.                                 fromupdate := false;            {reset the toggle}
  486.                                 endupdate(inputwindow);
  487.                                 setport(saveport);            {restore the port}
  488.                             END;     {updateEvt}
  489.                         OTHERWISE
  490.                     END;     {NewEvent.What}
  491.                 END;     {if}
  492.             systemTask;    {handle periodic stuff}
  493.         UNTIL HellFreezesOver;    {let it run for a good long time}
  494.     END; {EventLoop}
  495.  
  496. BEGIN
  497.     init;                {Init all toolbox stuff as well as application variables}
  498.     dowindows;        {draw the windows and setup 3D grafport}
  499.     domenus;        {do the menus}
  500.     identity;            {reset the transformation matrix (just in case)}
  501.     drawview;        {draw the contents of the view window}
  502.     drawinput;        {draw the contents of the control window}
  503.     eventloop;        {Handle the events}
  504. END.            {That's all for now…}